﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Reflection;
using System.Drawing;
using ArgusLib.Xml;
using ArgusLib.Drawing;

namespace ArgusLib.Fractals.OrbitFractals
{
	public class RendererBuddhabrot : Renderer<IDataSetPointDistribution, RenderParameterBuddhabrot>
	{
		delegate Color ColorProvider(float pixelCount, float range);

		#region Constructors
		public RendererBuddhabrot(RenderParameterBuddhabrot parameter)
			: base(parameter) { }
		#endregion

		#region Public Methods
		public override IDataSetProvider GetCompatibleDataSetProvider()
		{
			return new DataSetBuddhabrotProvider();
		}

		protected override void RenderCore(ExtendedBitmap image, IDataSet dataSet)
		{
			IDataSetPointDistribution dSet = (IDataSetPointDistribution)dataSet;
			image.Fill(this.Parameter.BackgroundColor);

			//float range = dataSet.MaxCount - dataSet.MinCount;
			//float range = 2 * (dataSet.Avarage - dataSet.MinCount);
			float range = (float)(2 * dSet.Variance * this.Parameter.RangeMultiplier);
			float average = dSet.Average + this.Parameter.OffsetMultiplier * range;
			float min = average - range / 2;
			float max = average + range / 2;

			ColorProvider GetColor = this.GetColorProvider();

			for (int x = 0; x < image.Width; x++)
			{
				for (int y = 0; y < image.Height; y++)
				{
					float pixelCount = System.Math.Max(dSet.PixelCount[x, y] - min, 0);
					Color c = GetColor(System.Math.Min(pixelCount, range), range);
					image.BlendPixel(x, y, c);
				}
			}
		}
		#endregion

		#region Non-Public Methods
		private ColorProvider GetColorProvider()
		{
			Type type = typeof(RendererBuddhabrot);
			MethodInfo mi = type.GetMethod("ColorProvider_" + this.Parameter.Coloring.ToString(), BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
			if (mi == null)
				return null;
			else if (mi.IsStatic == true)
				return Delegate.CreateDelegate(typeof(ColorProvider), mi) as ColorProvider;
			else
				return Delegate.CreateDelegate(typeof(ColorProvider), this, mi) as ColorProvider;
		}
		#endregion

		#region ColorProviders
		private static Color ColorProvider_RedYellow(float pixelCount, float range)
		{
			float x = pixelCount / range;
			x = x*3*255;
			byte a = (byte)System.Math.Min(x, 255);
			byte g = (byte)System.Math.Min(x - a, 255);
			byte b = (byte)(x - a - g);
			return Color.FromArgb(a, 255, g, b);
		}

		private Color ColorProvider_UserDefined(float pixelCount, float range)
		{
			if (this.Parameter.UserColors.Length < 1)
				return Color.Transparent;
			float x = (this.Parameter.UserColors.Length) * pixelCount / range;
			int i = (int)x;

			if (i == this.Parameter.UserColors.Length)
			{
				return this.Parameter.UserColors[this.Parameter.UserColors.Length - 1];
			}

			x = x - i;
			byte a = (byte)(x * this.Parameter.UserColors[i].A);

			if (i == 0)
			{
				return Color.FromArgb(a, this.Parameter.UserColors[0]);
			}
			
			Color dest = this.Parameter.UserColors[i - 1];
			if (this.Parameter.UserColors[i].A == 0)
			{
				return Color.FromArgb((byte)(dest.A*(1-x)), dest);
			}
			Color source = Color.FromArgb(a, this.Parameter.UserColors[i]);
			return ColorExtension.Blend(source, dest, BlendMode.Alpha);
		}
		#endregion
	}
}
